package org.example.managere.service.feibiao.impl;

import lombok.RequiredArgsConstructor;
import org.example.managere.dto.feibiao.AmArchivesRelationDto;
import org.example.managere.entity.feibiao.AmArchivesBase;
import org.example.managere.entity.feibiao.AmArchivesRelation;
import org.example.managere.repository.feibiao.AmArchivesBaseRepository;
import org.example.managere.repository.feibiao.AmArchivesRelationRepository;
import org.example.managere.service.feibiao.AmArchivesRelationService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 电机标准关联服务实现类
 */
@Service
@RequiredArgsConstructor
public class AmArchivesRelationServiceImpl implements AmArchivesRelationService {

    private final AmArchivesRelationRepository relationRepository;
    private final AmArchivesBaseRepository baseRepository;

    /**
     * 将实体转换为DTO
     */
    private AmArchivesRelationDto convertToDto(AmArchivesRelation relation) {
        AmArchivesRelationDto dto = new AmArchivesRelationDto();
        dto.setRelationId(relation.getRelationId());
        dto.setStandardType(relation.getStandardType());
        dto.setStandardValue(relation.getStandardValue());
        dto.setRelationDate(relation.getRelationDate());
        dto.setRemarks(relation.getRemarks());
        dto.setCreatedAt(relation.getCreatedAt());
        dto.setUpdatedAt(relation.getUpdatedAt());
        
        // 设置电机相关字段
        if (relation.getMotorId() != null) {
            dto.setMotorId(relation.getMotorId().getMotorId());
            dto.setMotorType(relation.getMotorId().getMotorType());
            dto.setManufacturer(relation.getMotorId().getManufacturer());
        }
        
        return dto;
    }

    /**
     * 将DTO转换为实体
     */
    private AmArchivesRelation convertToEntity(AmArchivesRelationDto dto) {
        AmArchivesRelation entity = new AmArchivesRelation();
        
        if (dto.getRelationId() != null) {
            entity.setRelationId(dto.getRelationId());
        }
        
        // 查找关联的电机基本信息
        AmArchivesBase motorBase = baseRepository.findById(dto.getMotorId())
                .orElseThrow(() -> new IllegalArgumentException("电机ID不存在: " + dto.getMotorId()));
        
        entity.setMotorId(motorBase);
        entity.setStandardType(dto.getStandardType());
        entity.setStandardValue(dto.getStandardValue());
        entity.setRelationDate(dto.getRelationDate());
        entity.setRemarks(dto.getRemarks());
        
        // 保留创建时间和更新时间（如果是更新操作）
        if (dto.getRelationId() != null) {
            Optional<AmArchivesRelation> existingRelation = relationRepository.findById(dto.getRelationId());
            if (existingRelation.isPresent()) {
                entity.setCreatedAt(existingRelation.get().getCreatedAt());
            }
        }
        
        return entity;
    }

    @Override
    @Transactional
    public AmArchivesRelationDto save(AmArchivesRelationDto amArchivesRelationDto) {
        // 检查是否已存在相同电机ID和标准类型的记录
        Optional<AmArchivesRelation> existingRelation = relationRepository.findByMotorId_MotorIdAndStandardType(
                amArchivesRelationDto.getMotorId(), amArchivesRelationDto.getStandardType());
        
        if (existingRelation.isPresent() && (amArchivesRelationDto.getRelationId() == null || 
                !amArchivesRelationDto.getRelationId().equals(existingRelation.get().getRelationId()))) {
            throw new IllegalArgumentException("该电机已经关联了同类型的标准: " + amArchivesRelationDto.getStandardType());
        }
        
        AmArchivesRelation entity = convertToEntity(amArchivesRelationDto);
        AmArchivesRelation savedEntity = relationRepository.save(entity);
        return convertToDto(savedEntity);
    }

    @Override
    @Transactional(readOnly = true)
    public Optional<AmArchivesRelationDto> findById(Integer relationId) {
        return relationRepository.findById(relationId)
                .map(this::convertToDto);
    }

    @Override
    @Transactional
    public AmArchivesRelationDto update(AmArchivesRelationDto amArchivesRelationDto) {
        // 确保记录存在
        if (amArchivesRelationDto.getRelationId() == null || 
                !relationRepository.existsById(amArchivesRelationDto.getRelationId())) {
            throw new IllegalArgumentException("无法更新不存在的记录，ID: " + amArchivesRelationDto.getRelationId());
        }
        
        // 检查是否与其他记录冲突（同一电机的相同标准类型）
        Optional<AmArchivesRelation> existingRelation = relationRepository.findByMotorId_MotorIdAndStandardType(
                amArchivesRelationDto.getMotorId(), amArchivesRelationDto.getStandardType());
        
        if (existingRelation.isPresent() && !existingRelation.get().getRelationId().equals(amArchivesRelationDto.getRelationId())) {
            throw new IllegalArgumentException("该电机已经关联了同类型的标准: " + amArchivesRelationDto.getStandardType());
        }
        
        AmArchivesRelation entity = convertToEntity(amArchivesRelationDto);
        AmArchivesRelation updatedEntity = relationRepository.save(entity);
        return convertToDto(updatedEntity);
    }

    @Override
    @Transactional
    public void deleteById(Integer relationId) {
        relationRepository.deleteById(relationId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findAll() {
        return relationRepository.findAll().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public Page<AmArchivesRelationDto> findAll(Pageable pageable) {
        Page<AmArchivesRelation> relationPage = relationRepository.findAll(pageable);
        List<AmArchivesRelationDto> dtoList = relationPage.getContent().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        return new PageImpl<>(dtoList, pageable, relationPage.getTotalElements());
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByMotorId(String motorId) {
        return relationRepository.findByMotorId_MotorId(motorId).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<AmArchivesRelationDto> findByMotorId(String motorId, Pageable pageable) {
        Page<AmArchivesRelation> relationPage = relationRepository.findByMotorId_MotorId(motorId, pageable);
        List<AmArchivesRelationDto> dtoList = relationPage.getContent().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        return new PageImpl<>(dtoList, pageable, relationPage.getTotalElements());
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByStandardType(String standardType) {
        return relationRepository.findByStandardType(standardType).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<AmArchivesRelationDto> findByStandardType(String standardType, Pageable pageable) {
        Page<AmArchivesRelation> relationPage = relationRepository.findByStandardType(standardType, pageable);
        List<AmArchivesRelationDto> dtoList = relationPage.getContent().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        return new PageImpl<>(dtoList, pageable, relationPage.getTotalElements());
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByStandardValue(String standardValue) {
        return relationRepository.findByStandardValueContaining(standardValue).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Page<AmArchivesRelationDto> findByStandardValue(String standardValue, Pageable pageable) {
        Page<AmArchivesRelation> relationPage = relationRepository.findByStandardValueContaining(standardValue, pageable);
        List<AmArchivesRelationDto> dtoList = relationPage.getContent().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        return new PageImpl<>(dtoList, pageable, relationPage.getTotalElements());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByDateRange(Date startDate, Date endDate) {
        return relationRepository.findByRelationDateBetween(startDate, endDate).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public Optional<AmArchivesRelationDto> findByMotorIdAndStandardType(String motorId, String standardType) {
        return relationRepository.findByMotorId_MotorIdAndStandardType(motorId, standardType)
                .map(this::convertToDto);
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<String> findAllStandardTypes() {
        return relationRepository.findAllDistinctStandardTypes();
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<String> findAllStandardValues() {
        return relationRepository.findAllDistinctStandardValues();
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<String> findMotorIdsByStandardTypeAndValue(String standardType, String standardValue) {
        return relationRepository.findMotorIdsByStandardTypeAndValue(standardType, standardValue);
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Long> countByStandardType() {
        List<Object[]> results = relationRepository.countGroupByStandardType();
        Map<String, Long> counts = new HashMap<>();
        
        for (Object[] result : results) {
            String standardType = (String) result[0];
            Long count = (Long) result[1];
            counts.put(standardType, count);
        }
        
        return counts;
    }
    
    @Override
    @Transactional(readOnly = true)
    public Map<String, Long> countStandardsByMotorId() {
        List<Object[]> results = relationRepository.countStandardsByMotorId();
        Map<String, Long> counts = new HashMap<>();
        
        for (Object[] result : results) {
            String motorId = (String) result[0];
            Long count = (Long) result[1];
            counts.put(motorId, count);
        }
        
        return counts;
    }
    
    @Override
    @Transactional(readOnly = true)
    public boolean checkMotorMeetsStandard(String motorId, String standardType) {
        return relationRepository.existsByMotorId_MotorIdAndStandardType(motorId, standardType);
    }
    
    @Override
    @Transactional
    public void deleteByMotorIdAndStandardType(String motorId, String standardType) {
        relationRepository.deleteByMotorId_MotorIdAndStandardType(motorId, standardType);
    }
    
    @Override
    @Transactional
    public void deleteAllByMotorId(String motorId) {
        relationRepository.deleteByMotorId_MotorId(motorId);
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByStandardCode(String standardCode) {
        return relationRepository.findByStandardValueContaining(standardCode).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(readOnly = true)
    public Page<AmArchivesRelationDto> findByStandardCode(String standardCode, Pageable pageable) {
        Page<AmArchivesRelation> relationPage = relationRepository.findByStandardValueContaining(standardCode, pageable);
        List<AmArchivesRelationDto> dtoList = relationPage.getContent().stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
        
        return new PageImpl<>(dtoList, pageable, relationPage.getTotalElements());
    }

    @Override
    @Transactional(readOnly = true)
    public List<AmArchivesRelationDto> findByComplianceStatus(String complianceStatus) {
        return relationRepository.findByStandardValueContaining(complianceStatus).stream()
                .map(this::convertToDto)
                .collect(Collectors.toList());
    }
} 